using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using RTMP.SimpleClient.Exceptions;

namespace RTMP.SimpleClient.Helpers
{
    /// <summary>
    /// RTMP 消息助手类
    /// </summary>
    public static class RTMPMessageHelper
    {

        public enum BasicCSID : byte
        {
            /// <summary>
            /// 控制消息（Chunk Stream ID 2）
            /// </summary>
            ProtocolControl = 2,

            /// <summary>
            /// 用户控制消息（Chunk Stream ID 3）
            /// </summary>
            UserControl = 3,

            /// <summary>
            /// AMF0 命令消息（Chunk Stream ID 4）
            /// </summary>
            CommandAFM0 = 4,

            /// <summary>
            /// AMF3 命令消息（Chunk Stream ID 5）
            /// </summary>
            CommandAFM3 = 5,
        }

        /// <summary>
        /// RTMP 消息类型枚举
        /// </summary>
        public enum RTMPMessageType : byte
        {
            /// <summary>
            /// 分块大小设置
            /// </summary>
            SetChunkSize = 0x01,

            /// <summary>
            /// 中止消息
            /// </summary>
            Abort = 0x02,

            /// <summary>
            /// 确认消息
            /// </summary>
            Acknowledgement = 0x03,

            /// <summary>
            /// 用户控制消息
            /// </summary>
            UserControl = 0x04,

            /// <summary>
            /// 窗口确认大小
            /// </summary>
            WindowAcknowledgementSize = 0x05,

            /// <summary>
            /// 设置对等带宽
            /// </summary>
            SetPeerBandwidth = 0x06,

            /// <summary>
            /// 边缘和起源服务器命令
            /// </summary>
            EdgeAndOriginServerCommand = 0x07,

            /// <summary>
            /// 音频消息
            /// </summary>
            Audio = 0x08,

            /// <summary>
            /// 视频消息
            /// </summary>
            Video = 0x09,

            /// <summary>
            /// AMF3 数据消息
            /// </summary>
            AMF3Data = 0x0F,

            /// <summary>
            /// AMF3 共享对象消息
            /// </summary>
            AMF3SharedObject = 0x10,

            /// <summary>
            /// AMF3 命令消息
            /// </summary>
            AMF3Command = 0x11,

            /// <summary>
            /// AMF0 数据消息
            /// </summary>
            AMF0Data = 0x12,

            /// <summary>
            /// AMF0 共享对象消息
            /// </summary>
            AMF0SharedObject = 0x13,

            /// <summary>
            /// AMF0 命令消息
            /// </summary>
            AMF0Command = 0x14,

            /// <summary>
            /// 聚合消息
            /// </summary>
            Aggregate = 0x16
        }

        /// <summary>
        /// 创建 RTMP 消息头
        /// </summary>
        /// <param name="messageType">消息类型</param>
        /// <param name="payloadLength">负载长度</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="streamId">流ID</param>
        /// <returns>消息头字节数组</returns>
        public static byte[] CreateMessageHeader(RTMPMessageType messageType, int payloadLength, uint timestamp, uint streamId)
        {
            // 消息头
            //14 00 00 00  // Message Type (20), Payload Length (26)
            //00 00 00 00  // Timestamp (0)
            //00 00 00     // Stream ID (0)

            using (var ms = new MemoryStream())
            using (var writer = new BinaryWriter(ms))
            {
                writer.Write((byte)messageType); // CommandType 1byte
                writer.Write(AMF0Helper.EncodeWithoutPrefix((uint)payloadLength), 1, 3); // Payload Length 3bytes
                writer.Write(AMF0Helper.EncodeWithoutPrefix(timestamp)); // Timestamp 4bytes
                writer.Write(AMF0Helper.EncodeWithoutPrefix(streamId), 1, 3); // Stream ID 3bytes

                return ms.ToArray();
            }
        }

        /// <summary>
        /// 从网络流中读取完整的 RTMP 消息
        /// </summary>
        /// <param name="stream">网络流</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>完整的消息数据</returns>
        public static async Task<byte[]> ReadMessageAsync(Stream stream, CancellationToken cancellationToken = default)
        {
            // 读取基本头
            var basicHeader = await ReadBytesAsync(stream, 1, cancellationToken);
            if (basicHeader.Length == 0)
                return Array.Empty<byte>();

            byte firstByte = basicHeader[0];
            int format = (firstByte >> 6) & 0x03;
            int chunkStreamId = firstByte & 0x3F;

            // 处理扩展分块流ID
            if (chunkStreamId == 0)
            {
                var extId = await ReadBytesAsync(stream, 1, cancellationToken);
                if (extId.Length == 0) return Array.Empty<byte>();
                chunkStreamId = 64 + extId[0];
            }
            else if (chunkStreamId == 1)
            {
                var extId = await ReadBytesAsync(stream, 2, cancellationToken);
                if (extId.Length < 2) return Array.Empty<byte>();
                chunkStreamId = 64 + extId[0] + (extId[1] << 8);
            }

            // 根据格式读取消息头
            RTMPMessageHeader header = new RTMPMessageHeader();

            if (format == 0) // 完整消息头 (11字节，基本头已读1字节)
            {
                var headerData = await ReadBytesAsync(stream, 11, cancellationToken);
                if (headerData.Length < 11) return Array.Empty<byte>();

                // 手动解析消息头
                using (var ms = new MemoryStream(headerData))
                using (var reader = new BinaryReader(ms))
                {
                    header.Timestamp = reader.ReadUInt32();
                    header.PayloadLength = reader.ReadUInt32();
                    header.MessageType = (RTMPMessageType)reader.ReadByte();
                    header.StreamId = reader.ReadUInt32();
                }
            }
            else if (format == 1) // 不包含消息流ID (7字节)
            {
                var headerData = await ReadBytesAsync(stream, 7, cancellationToken);
                if (headerData.Length < 7) return Array.Empty<byte>();

                using (var ms = new MemoryStream(headerData))
                using (var reader = new BinaryReader(ms))
                {
                    header.Timestamp = reader.ReadUInt32();
                    header.PayloadLength = reader.ReadUInt32();
                    header.MessageType = (RTMPMessageType)reader.ReadByte();
                    // StreamId 使用上一个消息的
                    header.StreamId = 0; // 简化实现
                }
            }
            else if (format == 2) // 只包含时间戳差值 (3字节)
            {
                var headerData = await ReadBytesAsync(stream, 3, cancellationToken);
                if (headerData.Length < 3) return Array.Empty<byte>();

                // 手动解析3字节的时间戳，使用BigEndianConverter
                var timestampBytes = new byte[4] { 0, headerData[0], headerData[1], headerData[2] };
                header.Timestamp = timestampBytes.AsSpan().BigEndianToUInt32();
                // 其他字段使用上一个消息的
                header.PayloadLength = 0;
                header.MessageType = RTMPMessageType.AMF0Command;
                header.StreamId = 0;
            }
            else if (format == 3) // 无消息头 (0字节)
            {
                // 使用上一个消息的所有字段
                header.Timestamp = 0;
                header.PayloadLength = 0;
                header.MessageType = RTMPMessageType.AMF0Command;
                header.StreamId = 0;
            }
            else
            {
                throw new RTMPException($"Unknown message format {format}");
            }

            // 处理扩展时间戳
            if (header.Timestamp == 0xFFFFFF)
            {
                var extTimestamp = await ReadBytesAsync(stream, 4, cancellationToken);
                if (extTimestamp.Length < 4) return Array.Empty<byte>();
                header.Timestamp = extTimestamp.AsSpan().BigEndianToUInt32();
            }

            // 读取消息体
            if (header.PayloadLength > 0)
            {
                var payload = await ReadBytesAsync(stream, (int)header.PayloadLength, cancellationToken);
                if (payload.Length != header.PayloadLength) return Array.Empty<byte>();
                return payload;
            }

            return Array.Empty<byte>();
        }

        /// <summary>
        /// 解析 RTMP 消息头
        /// </summary>
        /// <param name="data">消息数据</param>
        /// <returns>解析后的消息头信息</returns>
        public static RTMPMessageHeader ParseMessageHeader(byte[] data)
        {
            if (data == null || data.Length < 12)
            {
                throw new RTMPException("Invalid message header data");
            }

            using (var ms = new MemoryStream(data))
            using (var reader = new BinaryReader(ms))
            {
                // 跳过基本头
                reader.ReadByte();

                var header = new RTMPMessageHeader
                {
                    Timestamp = reader.ReadUInt32(),
                    PayloadLength = reader.ReadUInt32(),
                    MessageType = (RTMPMessageType)reader.ReadByte(),
                    StreamId = reader.ReadUInt32()
                };

                return header;
            }
        }

        /// <summary>
        /// 从流中读取指定数量的字节
        /// </summary>
        private static async Task<byte[]> ReadBytesAsync(Stream stream, int count, CancellationToken cancellationToken)
        {
            var buffer = new byte[count];
            int totalRead = 0;

            while (totalRead < count)
            {
                int bytesRead = await stream.ReadAsync(buffer, totalRead, count - totalRead, cancellationToken);
                if (bytesRead == 0)
                    break;

                totalRead += bytesRead;
            }

            if (totalRead != count)
            {
                Array.Resize(ref buffer, totalRead);
            }

            return buffer;
        }

        /// <summary>
        /// RTMP 消息头结构
        /// </summary>
        public struct RTMPMessageHeader
        {
            public uint Timestamp;
            public uint PayloadLength;
            public RTMPMessageType MessageType;
            public uint StreamId;
        }
    }
}
